package cn.edu.sjtu.se.dslab.dao.impl;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.exception.JDBCConnectionException;
import org.hibernate.exception.LockAcquisitionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate3.HibernateQueryException;
import org.springframework.stereotype.Repository;

import cn.edu.sjtu.se.dslab.action.bean.PageBean;
import cn.edu.sjtu.se.dslab.dao.IBaseDao;
import cn.edu.sjtu.se.dslab.exception.DBException;
import cn.edu.sjtu.se.dslab.util.DBMessage;

@Repository("baseDao")
public class BaseDaoImpl<T extends Serializable> implements IBaseDao<T> {

	protected Logger logger = LoggerFactory.getLogger(getClass());

	@PersistenceContext
	EntityManager em;

	public void delById(Class<T> clazz, long id) {
		em.remove(em.find(clazz, id));
	}

	public void save(T t) {
		//em.getTransaction().begin();
		em.persist(t);
		//em.getTransaction().commit();
	}

	public T update(T t) {
		return em.merge(t);
	}

	/**
	 * query the object by primary key : id
	 * 
	 * @param id
	 * @param clazz
	 * @return
	 */
	public T queryById(Class<T> clazz, long id) {
		return em.find(clazz, id);
	}

	@SuppressWarnings("unchecked")
	public List<T> queryList(String clazz) {
		String hql = "from " + clazz + " c order by c.id desc";
		return em.createQuery(hql).getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<T> queryList(int pageNo, int pageSize, String clazz) {
		String hql = "from " + clazz + " c order by c.id desc";
		Query query = em.createQuery(hql);
		query.setMaxResults(pageSize);
		query.setFirstResult((pageNo - 1) * pageSize);
		return query.getResultList();
	}

	public long countAll(String clazz, short status, String columnName) {
		String hql = null;
		if (-1 == status) {
			hql = "select count(c) from " + clazz + " as c";
		} else {
			hql = "select count(c) from " + clazz + " as c where c."
					+ columnName + "=" + status;
		}
		Query query = em.createQuery(hql);
		Long totalNumber = (Long) query.getSingleResult();
		return totalNumber;
	}

	@SuppressWarnings("unchecked")
	public List<T> query(String hql) {
		return em.createQuery(hql).getResultList();
	}

	@SuppressWarnings("unchecked")
	public T queryObject(String hql) {
		List<T> objectList = em.createQuery(hql).getResultList();
		if (objectList.size() > 0) {
			return objectList.get(0);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public List<T> querySpecialList(int pageNo, int pageSize, String hql) {
		Query query = em.createQuery(hql);
		query.setMaxResults(pageSize);
		query.setFirstResult((pageNo - 1) * pageSize);
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<T> querySpecialListByDate(int pageNo, int pageSize, String hql,
			String dateName) {
		Date date = new Date();
		Query query = em.createQuery(hql);
		query.setMaxResults(pageSize);
		query.setFirstResult((pageNo - 1) * pageSize);
		query.setParameter(dateName, date);
		return query.getResultList();
	}

	/**
	 * 根据hql语句查询信息（分页）<BR>
	 * 
	 * @param 当前页起始索引hql语句
	 * @return 查询结果(List类型List)
	 */
	public PageBean<T> queryByHqlForPage(int pageNum, int pageSize, String clazz)
			throws DBException {
		// 定义返回值
		PageBean<T> pageBean = new PageBean<T>();
		// 总记录数
		int allRow = queryList(clazz).size();

		// 总页数
		int totalPage = PageBean.countTotalPage(pageSize, allRow);

		// 当前页开始记录
		int start = PageBean.countOffset(pageSize, pageNum);

		// 当前页号
		int currentPage = PageBean.countCurrentPage(pageNum);

		try {

			// 查询数据
			List<T> list = queryList(pageNum, pageSize, clazz);
			int size = list == null ? 0 : list.size();
			// 把分页信息保存到Bean中
			// 页面大小
			pageBean.setPageSize(pageSize);

			// 页面起始记录数
			pageBean.setStart(start);

			// 页面结束记录数
			pageBean.setEnd(start + size);

			// 设置当前页
			pageBean.setCurrentPage(currentPage);

			// 设置总记录数
			pageBean.setAllRow(allRow);

			// 设置总页数
			pageBean.setTotalPage(totalPage);

			// 设置结果集
			pageBean.setList(list);

			// 返回list
			return pageBean;
		} catch (JDBCConnectionException e) {
			// 如果连接数据库失败抛出DBException并且传入消息Code
			throw new DBException(DBMessage.DBCONNECT_RETRYOVER);
		} catch (LockAcquisitionException e) {
			// 如果连接数据库失败抛出DBException并且传入消息Code
			throw new DBException(DBMessage.DBCONNECT_RETRYOVER);
		} catch (HibernateQueryException e) {
			// 如果hql语句出现问题抛出DBException并且传入消息
			throw new DBException(DBMessage.EXECUTE_SELECT);
		} catch (Exception e) {
			// 出现除以上情况的其它情况抛出异常对象
			e.printStackTrace();
			throw new DBException(DBMessage.E_OTHER);
		}
	}
	
	/**
	 * 根据hql语句查询信息（分页）<BR>
	 * 
	 * @param 当前页起始索引hql语句
	 * @return 查询结果(List类型List)
	 */
	public PageBean<T> queryByspecialHqlForPage(int pageNum, int pageSize, String hql)
			throws DBException {
		// 定义返回值
		PageBean<T> pageBean = new PageBean<T>();
		// 总记录数
		int allRow = query(hql).size();

		// 总页数
		int totalPage = PageBean.countTotalPage(pageSize, allRow);

		// 当前页开始记录
		int start = PageBean.countOffset(pageSize, pageNum);

		// 当前页号
		int currentPage = PageBean.countCurrentPage(pageNum);

		try {

			// 查询数据
			List<T> list = querySpecialList(pageNum, pageSize, hql);
			int size = list == null ? 0 : list.size();
			// 把分页信息保存到Bean中
			// 页面大小
			pageBean.setPageSize(pageSize);

			// 页面起始记录数
			pageBean.setStart(start);

			// 页面结束记录数
			pageBean.setEnd(start + size);

			// 设置当前页
			pageBean.setCurrentPage(currentPage);

			// 设置总记录数
			pageBean.setAllRow(allRow);

			// 设置总页数
			pageBean.setTotalPage(totalPage);

			// 设置结果集
			pageBean.setList(list);

			// 返回list
			return pageBean;
		} catch (JDBCConnectionException e) {
			// 如果连接数据库失败抛出DBException并且传入消息Code
			throw new DBException(DBMessage.DBCONNECT_RETRYOVER);
		} catch (LockAcquisitionException e) {
			// 如果连接数据库失败抛出DBException并且传入消息Code
			throw new DBException(DBMessage.DBCONNECT_RETRYOVER);
		} catch (HibernateQueryException e) {
			// 如果hql语句出现问题抛出DBException并且传入消息
			throw new DBException(DBMessage.EXECUTE_SELECT);
		} catch (Exception e) {
			// 出现除以上情况的其它情况抛出异常对象
			e.printStackTrace();
			throw new DBException(DBMessage.E_OTHER);
		}
	}

	@Override
	public void delete(T t) {
		// TODO Auto-generated method stub
		//em.remove(em.contains(t) ? t : em.merge(t));
		em.remove(t);
	}
}
